﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace Practicum_2
{

    public class Program {

        Bitmap smurf1;
        Bitmap smurf2;
        Bitmap smurf3;
        Bitmap smurf4;
        Bitmap smurf_new;
        Bitmap bw1;
        Bitmap bw2;
        Bitmap bw3;
        Bitmap bw4;
        Bitmap bw_new;
        List<DataPoint> allDataPoints = new List<DataPoint>();
        DecisionTree dt;

        int patchGrootte;

	    public static void Main(String[] args) {

            Program p = new Program();
            DateTime dt = DateTime.Now;
            Console.WriteLine("started at: " + dt.Hour + ":" + dt.Minute);
            p.laadPlaatje("black-smurf.jpg", ref p.smurf1);
            p.laadPlaatje("mopper_smurf.jpg", ref p.smurf2);
            p.laadPlaatje("smurfen-salade.gif", ref p.smurf3);
            p.laadPlaatje("smurfin.jpg", ref p.smurf4);
            p.laadPlaatje("black-smurf_.jpg", ref p.bw1);
            p.laadPlaatje("mopper_smurf_.jpg", ref p.bw2);
            p.laadPlaatje("smurfen-salade_.gif", ref p.bw3);
            p.laadPlaatje("smurfin_.jpg", ref p.bw4);
            int patch;
            Int32.TryParse(args[1], out patch);
            p.setPatchGrootte(patch);
            p.createDataPointsFromBitmap(p.smurf1, p.bw1);
            p.createDataPointsFromBitmap(p.smurf2, p.bw2);
            p.createDataPointsFromBitmap(p.smurf3, p.bw3);
            p.createDataPointsFromBitmap(p.smurf4, p.bw4);
            p.dt = new DecisionTree(p.allDataPoints);
            Console.WriteLine("Don't mind me, I'm building a tree...");
            p.dt.partitionRecursively(p.allDataPoints.Count * 2 / 100); //2% van alle pixels
            Console.WriteLine("Generating image...");
            p.zoekSmurf(args[0]);
            if (args[2] != null) Console.WriteLine("Prediction " + p.testTree(args[2]) + "% correct!");
            TimeSpan ts = DateTime.Now - dt;
            Console.WriteLine("\nTime elapsed: " + ts.Minutes + ":" + (ts.Seconds % 60));
            Console.ReadKey();
            
        }

        void createDataPointsFromBitmap(Bitmap bitmap, Bitmap bw)
        {
            for (int y = 0; y < bitmap.Height; y++)
            {
                for (int x = 0; x < bitmap.Width; x++)
                {
                    int cl;
                    if (bw.GetPixel(x, y).GetBrightness() >= 1) cl = 1; else cl = 0;
                    allDataPoints.Add(new DataPoint(30, createHistogramFromPatch(bitmap, x, y), cl));
                }
            }
        }

        void laadPlaatje(string filename, ref Bitmap smurf)
        {
            // Plaatje wordt ingeladen, als dit mislukt wordt er een foutmelding gegeven.
            try
            {
                smurf = (Bitmap)Image.FromFile(filename);
            }
            catch (Exception e)
            {
                Console.WriteLine("File could not be loaded: " + e.Message);
                Environment.Exit(-1);
            }
        }

        void setPatchGrootte(int patchGrootte)
        {
            this.patchGrootte = patchGrootte;
        }

        DataPoint createDataPoint(int x, int y, int cl)
        {
            int noOfAttributes = 30;
            double[] attributes = createHistogramFromPatch(smurf1, x, y);

            return new DataPoint(noOfAttributes, attributes, cl);
        }

        double[] createHistogramFromPatch(Bitmap plaatje, int px, int py)
        {
            double[] histogram = new double[30];
            double[] histogramH = new double[10];
            double[] histogramS = new double[10];
            double[] histogramV = new double[10];
            int pixelsInPatch = patchGrootte * patchGrootte;
            for (int x = px - patchGrootte / 2; x <= (patchGrootte / 2) + px; x++)
            {
                for (int y = py - patchGrootte / 2; y <= (patchGrootte / 2) + py; y++)
                {
                    if (x < 0 || x >= plaatje.Width || y < 0 || y >= plaatje.Height)
                    {
                        pixelsInPatch--;
                    }
                    else
                    {
                        Color c = plaatje.GetPixel(x, y);
                        histogramH[(int)(c.GetHue() * 9 / 360)]++;
                        histogramS[(int)(c.GetSaturation() * 9)]++;
                        histogramV[(int)(c.GetBrightness() * 9)]++;
                    }
                }
            }

            int ix = 0;
            for (int i = 0; i < 10; i++)
            {
                histogram[ix] = histogramH[i];
                histogram[ix + 10] = histogramS[i];
                histogram[ix + 20] = histogramV[i];
                ix++;
            }

            for (int i = 0; i < 30; i++)
            {
                histogram[i] /= (pixelsInPatch);
            }

            return histogram;
        }

        void zoekSmurf(String filename)
        {
            smurf_new = (Bitmap)Image.FromFile(filename);
            bw_new = new Bitmap(smurf_new.Width, smurf_new.Height);
            allDataPoints.Clear();
            createDataPointsFromBitmap(smurf_new, bw_new);
            for (int x = 0; x < smurf_new.Width; x++)
            {
                for (int y = 0; y < smurf_new.Height; y++)
                {
                    if (dt.getClassLabel(allDataPoints[y * smurf_new.Width + x]) == 0)
                    {
                        bw_new.SetPixel(x, y, Color.Black);
                    }
                    else
                    {
                        bw_new.SetPixel(x, y, smurf_new.GetPixel(x, y));
                    }
                }
            }
            bw_new.Save("bw_" + filename);
        }

        int testTree(String bw_testfile)
        {
            Bitmap bw_test = (Bitmap)Image.FromFile(bw_testfile);

            int correctCount = 0;

            for (int x = 0; x < smurf_new.Width; x++)
            {
                for (int y = 0; y < smurf_new.Height; y++)
                {
                    if (bw_new.GetPixel(x, y).GetBrightness() == 0 && bw_test.GetPixel(x, y).GetBrightness() == 0) correctCount++;
                    if (bw_new.GetPixel(x, y).GetBrightness() != 0 && bw_test.GetPixel(x, y).GetBrightness() != 0) correctCount++;
                }
            }

            int total = smurf_new.Height * smurf_new.Width;
            return  correctCount * 100 / total;
        }
    }  
}
